home *** CD-ROM | disk | FTP | other *** search
- Chapter 13 - Modules, Local and Global
-
-
-
- PREREQUISITES FOR THIS MATERIAL
-
- Before attempting to understand this material, you
- should have a good grasp of the principles taught in Part I
- of this tutorial. None of the material from Part II is
- required to do a meaningful study of modules in Modula-2.
-
- WHAT GOOD ARE MODULES?
-
- Modules are the most important feature of Modula-2 over
- its predecessor Pascal making it very important for you to
- understand what they are and how they work. Fortunately for
- you, there are not too many things to learn about them and
- after you master them you will find many uses for them as
- you develop programs, and especially large programs.
-
- Load and display the program named LOCMOD1.MOD for your
- first example of a program with an embedded module.
- Modules are nothing new to you because every program you
- have examined has been a module. At this time, however, we
- will introduce a local module.
-
- WHAT IS A LOCAL MODULE?
-
- A local module is simply a module nested within another
- module, just like the example on your monitor at this time.
- The module named "LocalStuff" is nested within the main
- module and is heavily indented for clarity. Since nothing
- is imported into the local module, nothing that belongs to
- the main module can be seen from within the nested module.
- In addition, since the procedure "GetNumber" is the only
- thing exported from the local module, nothing else is
- available to the main module. In effect, the local module
- is an impenetrable wall through which nothing can pass
- without the benefit of the IMPORT and EXPORT list. In this
- case, the variable "Counter" cannot be modified in any way
- by the main module, either intentionally or accidentally and
- the procedure "GetNumber" will very stubbornly refuse to
- allow any flexibility in its output, adding three to its
- internally stored variable each time it is called. It may
- seem to you that this result can be accomplished easily by
- using another procedure without the module but we will see
- shortly that it will not be the same.
-
- THE BODY OF THE LOCAL MODULE
-
- The body of the local module has one statement
- contained within it, "Counter := 4;", that is executed only
- when the module is loaded, and at no other time. This is
- therefore an initialization section for the module. Any
-
-
- Page 81
-
-
-
-
-
-
-
-
-
- Chapter 13 - Modules, Local and Global
-
-
- valid statements can be put here and they will be executed
- when the program is loaded, or you can omit the body
- altogether by omitting the BEGIN and any statements.
- Actually, this body is no different than the body of the
- main program since it too is executed one time when the
- program is loaded, except for the fact that the main program
- is required to have a body or you will have no program.
-
- THE MODULE VERSUS THE PROCEDURE
-
- We must digress a bit to see the difference in these
- two important topics in Modula-2. A procedure is an
- executable section of code whereas a module is a grouping of
- variables, constants, types, and procedures. A module is
- never executed since it is simply a grouping identifier.
-
- The variables in a procedure do not exist when it is
- not being executed, but instead are generated dynamically
- when the procedure is called. A variable therefore, has a
- lifetime associated with it in addition to a "type". This
- may seem strange to you but if you think about it for
- awhile, it will help explain how recursive procedure calls
- work. The module, on the other hand, exists anytime its
- surrounding code exists, in this case, the main program.
- Since the module always exists, the variable "Counter" also
- always exists because it is defined as a part of the module.
- If this variable were defined within a procedure, it would
- be automatically regenerated every time the procedure were
- called and would therefore not remember the value it
- contained the prior time the procedure was called. We could
- choose to define the variable as global and it would
- therefore always be available and never regenerated, but we
- would be left with the possibility of anything in the
- program modifying it either accidentally or on purpose. In
- a program as small as this one, it would not be a problem,
- but it is intended to illustrate the solution to a problem
- embedded in a much larger program.
-
- Suppose, for example, that you wished to generate
- random numbers for some use within a program. You could
- include all of the code within a module using the module
- body for the seed initialization, and a procedure to
- generate one random number each time it was called. The
- structure would be essentially the same as that given here,
- but the actual code would be different. Nothing in the main
- program or any of its procedures could in any way corrupt
- the job given to the random number generator.
-
- BACK TO THE PROGRAM ON YOUR MONITOR
-
- In this case we have one local module defined within
-
-
- Page 82
-
-
-
-
-
-
-
-
-
- Chapter 13 - Modules, Local and Global
-
-
- the main module but as many as desired could be used, and we
- have one procedure in the local module whereas we could have
- as many as desired. In fact, we could have local modules
- embedded in a procedure, or in other local modules. There
- is no real limit as to how you can structure your program to
- achieve the desired results. One thing must be remembered.
- If you embed a local module within a procedure, all of its
- variables are defined dynamically each time the procedure in
- which it is embedded is called, and its body is also
- executed each time. This can be used to advantage in some
- situations, but it would be best to leave this construct to
- the future when you have more experience with Modula-2.
-
- In the body of the main module you will find nothing
- new except for the call to the function procedure
- "GetNumber()" which is actually nothing new except that it
- is embedded in the local module "LocalStuff". Compile and
- run the program to see if it does what you expect it to do.
-
- TWO LOCAL MODULES
-
- It would be well to point out at this time that if you
- define two local modules at the same level, one could EXPORT
- a variable, procedure, constant, or type and the other could
- IMPORT it and use it in any legal fashion. You therefore
- have the ability to very carefully define the mechanism by
- which the two modules interact.
-
- ANOTHER LOCAL MODULE
-
- The program we have been inspecting had the procedure
- exported without qualification, so it could only be referred
- to by its simple name. This could have led to a naming
- conflict which can be solved by using a qualified export as
- is done in the next program. Load and display the program
- named LOCMOD2.MOD. This program is very similar to the last
- except for moving the output statements to the procedure.
-
- First, you should notice that the procedure name is
- exported using "EXPORT QUALIFIED" which allows the use of
- the qualified call to the procedure in line number 25.
- There can never be a conflict of names in calling a
- procedure this way because it is illegal to use the same
- name for a module more than once at any level. In a local
- module, you have a choice of using either qualified or
- unqualified export of items, but the exported items must all
- be of the same export type because only one export list is
- allowed per module.
-
-
-
-
-
- Page 83
-
-
-
-
-
-
-
-
-
- Chapter 13 - Modules, Local and Global
-
-
- IMPORTING INTO A LOCAL MODULE
-
- The three output procedures are used in the local
- module "MyStuff", but because it is only permissible to
- import items from a module's immediate surroundings, the
- procedures must first be imported into the main module.
-
- The procedure named "WriteStuff" is even more tightly
- controlled than that in the last program because this one
- doesn't even return a value to the calling program. It
- updates its own internally stored value, displays it, and
- returns control to the calling program.
-
- Compile and run this program, then we will go on to
- global modules.
-
- GLOBAL MODULES
-
- As useful as local modules are, they must take a back
- seat to the global module with which you are already fairly
- familiar because you have been using them throughout this
- tutorial. The modules "InOut", "Terminal", and "FileSystem"
- are examples of global modules that you already know how to
- use. Now you will learn how to write your own global
- modules that can be called in exactly the same way as these
- standard modules from any program.
-
- YOUR FIRST DEFINITION MODULE
-
- In order to get started, load and display the program
- named CIRCLES.DEF on your monitor. The first thing you will
- notice is that we used a different extension for this
- program because there is another part to the program with
- the same name but the usual extension "MOD". What you have
- displayed on your screen is the definition part of the
- global module and it serves two very important purposes.
- First, it defines the interface you need to use the module
- in one of your programs, and it defines the details of the
- interface for the compiler so it can do type checking for
- you when you call this module. The Modula-2 compiler uses
- the information contained here to check all types and
- numbers of variables just like it would do in a singly
- compiled program.
-
- The program on your monitor does very little. In fact
- its purpose is to do nothing because there are no executable
- statements in it. It is only to define the interface to the
- actual program statements contained elsewhere. Notice that
- the procedures are exported using the qualified option.
- All identifiers that are exported from a definition module
- must be qualified so that the user has the option of
-
-
- Page 84
-
-
-
-
-
-
-
-
-
- Chapter 13 - Modules, Local and Global
-
-
- importing them either way. It is legal to export
- procedures, variables, constants, or types for use elsewhere
- as needed for the programming problem at hand, but the
- majority of exported items are procedures. It should be
- obvious that nothing within the module is available to any
- other part of the program unless it is exported.
-
- THE IMPLEMENTATION MODULE
-
- We are not finished with the definition part of the
- module yet but we will look at the implementation part of it
- for a few moments. Load the program named CIRCLES.MOD and
- display it on your monitor. This is the part of the module
- that actually does the work. Notice that there are three
- procedures here, two of which were defined in the definition
- part of the module making them available to other programs.
- The procedure named "GetPi" is a hidden or private procedure
- that is only available for use within this module. The
- other two procedures are available to any program that
- wishes to use them simply by importing them.
-
- Anything defined in the definition part of the module
- is also available here for use without redefining it, except
- for the procedure headers which must be completely defined
- in both places. Anything imported into the definition part
- of the module must also be imported here if it will be used
- in this module, imported identifiers are not automatically
- transferred into this part of the module.
-
- MORE ABOUT THE USE OF TWO PARTS
-
- The definition part of the module defines the public
- information about the module and the implementation part of
- the module defines the private or hidden information about
- the module. It may seem sort of silly to go to the trouble
- of separating a module into two parts but there are at least
- three good reasons to do so.
-
- 1. You may not care how the module is implemented.
-
- In all of the programs we have run up to this point,
- you probably didn't care how the "WriteString"
- procedure did its job. You only wanted it to do the
- job it was supposed to do to aid you in learning to use
- Modula-2 efficiently. It would have been senseless to
- have cluttered your monitor with the details of how it
- worked every time you wanted to know how to use it.
-
- 2. It hides details of implementation.
-
- If you were working on a large programming project and
-
-
- Page 85
-
-
-
-
-
-
-
-
-
- Chapter 13 - Modules, Local and Global
-
-
- you were assigned to job of writing a procedure for
- others to use that did some well defined task, you
- would define the interface carefully and be finished.
- If, however, one of the users studied your detailed
- code and found a way to trick it into doing something
- special, he may use the trick in his part of the
- program. If you then wanted to improve your routine
- and remove the code that allowed the trick, the
- interface would no longer work. To prevent this, you
- give others only the interface to work with and they
- cannot look for tricks. This is called "information
- hiding" and is a very important technique which is used
- on large projects.
-
- 3. It allows for orderly development.
-
- It is possible to define all of the definition parts of
- the modules and have all members of the development
- team agree to the interface. Long before the details
- of the individual procedures are worked out, the entire
- team knows what each procedure will do and they can all
- begin work on their respective parts of the overall
- system. This is very effective when used on a large
- team effort.
-
- COMPILATION ORDER IS IMPORTANT
-
- In order for the above principles to work effectively,
- a very definite order of compilation must be adhered to. If
- the identifiers declared in the definition part are
- automatically available in the implementation part of the
- module, then it is obvious that the definition part must be
- compiled before the implementation part of the module can be
- compiled. Also, if the definition part is modified and
- recompiled, then the implementation part may also require
- modifications to comply with the changes and it must also be
- recompiled.
-
- The next rule is not nearly so obvious but you will
- understand it when we explain it. When a calling module is
- compiled, it checks each of the imported identifiers to see
- that the types and number of variables agree with the
- calling sequences used in the program. This is part of the
- strong "type checking" done for you by Modula-2. If you
- modify and recompile one of the called definition modules
- and attempt to relink the program together, you may have
- introduced a type incompatibility. In order to prevent
- this, Modula-2 requires you to recompile every module that
- calls a modified definition module. It does this by
- generating a "key" when you compile a definition module and
- storing the "key" when you compile the calling module. If
-
-
- Page 86
-
-
-
-
-
-
-
-
-
- Chapter 13 - Modules, Local and Global
-
-
- you attempt to link a program with differing "keys", this
- indicates that the definition module was changed, resulting
- in a new "key" and hence a mismatch, and the linker will
- generate an error.
-
- WHY ALL OF THIS TROUBLE?
-
- It may not seem to be worth all of the extra trouble
- that the Modula-2 compiler and linker go through to do this
- checking but it is important for a large program. The
- information used in the definition part of the module is the
- type of information that should be well defined in the
- design stages of a programming project, and if well done,
- very few or no changes should be required during the coding
- phase of the project. Therefore it is expected that
- recompiling several definition modules should not happen
- very often. On the other hand, during the coding and
- debugging phase of the project, it is expected that many
- changes will be required in the implementation parts of the
- modules. Modula-2 allows this and still maintains very
- strong type checking across module boundaries to aid in
- detecting sometimes very subtle coding errors.
-
- The above paragraph should be interpreted as a warning
- to you. If you find that you are constantly recompiling
- modules due to changes in the definition modules, you should
- have spent more time in the software design.
-
- NOW TO ACTUALLY USE IT ALL
-
- With all of that in mind, it will be necessary for you
- to reload the program named CIRCLES.DEF which is the
- definition part of the module, and compile it. Your
- compiler will generate several different files for use in
- cross checking. After you get a good compile, reload the
- program named CIRCLES.MOD which is the implementation part
- of the module and compile it. During this compile, some of
- the files generated by CIRCLES.DEF will be referred to. It
- would be an interesting exercise to modify a procedure call
- in one of the programs to see what kind of an error is
- displayed. After a good compile on both of these modules,
- you have a new module in your library that can be used just
- like any of the other global libraries that came with your
- compiler.
-
- Load and display the program GARDEN.MOD for an example
- of a program that calls your new library or global module.
- This program is very simple and should pose no problem in
- understanding for you. The two new procedures are imported
- and used just like any other procedure. Compile and run
- this program.
-
-
- Page 87
-
-
-
-
-
-
-
-
-
- Chapter 13 - Modules, Local and Global
-
-
-
- A FINAL WORD ABOUT GLOBAL MODULES
-
- From the above description of global modules, it may
- not be very obvious to you that it is perfectly legal for
- one global module to call another which in turn calls
- another, etc. Program structure is entirely up to you. For
- example, we could have called "WriteString" and some of our
- other familiar procedures from within the "AreaOfCircle"
- procedure. The order of compilation must be kept in mind or
- you will not get a good compilation and linking of your
- completed program.
-
- Remember that there is nothing magic about the global
- or library (the names are synonymous) modules supplied with
- your compiler. They are simply global modules that have
- already been programmed and debugged for you by the compiler
- writer. This is probably a good time to mention to you that
- you may have only received the source code for the
- definition part of the library modules with your compiler.
- Many compiler writers will supply the source code for the
- implementation part of the library modules only if you
- supply them with a little more money. After all, they are
- in business for the money and most people never wish to
- modify the supplied routines but are happy to use them as
- is. All compiler writers will supply you with the
- definition part of the library modules because they are your
- only means of interfacing with them.
-
- THE PROCEDURE TYPE, SOMETHING NEW
-
- Load and display the program named PROCTYPE.MOD on your
- monitor for an example of a procedure TYPE. In line 6 we
- define a variable "OutputStuff" to be a PROCEDURE type of
- variable that requires an "ARRAY OF CHAR" as an argument.
- This variable name can now be used to refer to any procedure
- that uses a single "ARRAY OF CHAR" as an argument.
-
- In the definition part of the program two procedures
- are defined, each of which uses a single "ARRAY OF CHAR" as
- an argument. Then in the main program the variable
- "OutputStuff" is assigned each of the new procedures and
- used to call them. In addition, it is used to call the
- supplied procedure "WriteString" to illustrate the
- possibility of doing so. Finally, the procedures are all
- called in their normal manner to illustrate that there is
- nothing magic about them. Any procedure type can be used to
- call any procedures that use the same type of parameter
- calls as those defined when it is created as a variable.
-
-
-
-
- Page 88
-